<script lang="ts">
	import { onMount } from 'svelte';
	import { page } from '$app/stores';
	import { getHistory, getServiceStats, listServices } from '$lib/api';
	import { subscribeHeartbeats } from '$lib/realtime';
	import type { Service, Heartbeat, ServiceStats } from '$lib/types';

	let svc: Service | undefined = $state();
	let chartHistory: Heartbeat[] = $state([]);
	let stats: ServiceStats | null = $state(null);
	let loading = $state(true);

	let tableData: Heartbeat[] = $state([]);
	let currentPage = $state(1);
	let totalPages = $state(1);
	let totalItems = $state(0);

	let expandedError: number | null = $state(null);

	const PER_PAGE = 50;

	async function loadTablePage(pageNum: number) {
		const res = await getHistory(Number($page.params.id), pageNum, PER_PAGE);
		tableData = res.data;
		currentPage = res.page;
		totalPages = res.total_pages;
		totalItems = res.total;
	}

	onMount(async () => {
		try {
			const all = await listServices();
			svc = all.find((s) => s.id === Number($page.params.id));

			const chartRes = await fetch(`/api/services/${$page.params.id}/history?page=1&per_page=50`);
			if (chartRes.ok) {
				const json = await chartRes.json();
				chartHistory = json.data ?? json;
			}

			getServiceStats(Number($page.params.id)).then((s) => (stats = s)).catch(() => {});

			await loadTablePage(1);
		} catch {
			// handle
		} finally {
			loading = false;
		}
	});

	onMount(() => {
		const unsub = subscribeHeartbeats((hb) => {
			if (hb.service_id !== Number($page.params.id)) return;
			chartHistory = [...chartHistory, hb].slice(-50);
			if (currentPage === 1) {
				tableData = [hb, ...tableData].slice(0, PER_PAGE);
				totalItems++;
				totalPages = Math.max(1, Math.ceil(totalItems / PER_PAGE));
			}
		});
		return unsub;
	});

	let containerWidth = $state(0);
	let pad = { t: 8, b: 24, l: 44, r: 12 };
	let chartH = 200;
	let plotW = $derived(Math.max(containerWidth - pad.l - pad.r, 0));
	let plotH = $derived(chartH - pad.t - pad.b);

	function niceNum(range: number, round: boolean): number {
		const exp = Math.floor(Math.log10(range));
		const frac = range / Math.pow(10, exp);
		let nice: number;
		if (round) {
			if (frac <= 1.5) nice = 1;
			else if (frac <= 3) nice = 2;
			else if (frac <= 7) nice = 5;
			else nice = 10;
		} else {
			if (frac <= 1) nice = 1;
			else if (frac <= 2) nice = 2;
			else if (frac <= 5) nice = 5;
			else nice = 10;
		}
		return nice * Math.pow(10, exp);
	}

	let yAxis = $derived.by(() => {
		const vals = chartHistory.map((h) => h.response_time_ms);
		if (vals.length === 0) return { min: 0, max: 100, ticks: [{ val: 0, y: 0 }, { val: 100, y: 200 }] };
		const rawMin = Math.min(...vals);
		const rawMax = Math.max(...vals);
		if (rawMax === rawMin) return { min: 0, max: Math.max(rawMax * 2, 100), ticks: [] };

		const range = rawMax - rawMin;
		const pad = Math.max(range * 0.15, 10);
		let lo = Math.max(0, rawMin - pad);
		let hi = rawMax + pad;

		const tickStep = niceNum((hi - lo) / 4, true);
		lo = Math.floor(lo / tickStep) * tickStep;
		hi = Math.ceil(hi / tickStep) * tickStep;

		const ticks: { val: number; y: number }[] = [];
		for (let v = lo; v <= hi + tickStep * 0.001; v += tickStep) {
			const y = pad.t + plotH - ((v - lo) / (hi - lo || 1)) * plotH;
			ticks.push({ val: Math.round(v), y });
		}
		return { min: lo, max: hi, ticks };
	});

	let segments = $derived.by(() => {
		const n = chartHistory.length;
		if (n < 2) return [];
		const { min, max } = yAxis;
		return chartHistory.slice(0, -1).map((h, i) => {
			const next = chartHistory[i + 1];
			const x1 = pad.l + (i / (n - 1)) * plotW;
			const x2 = pad.l + ((i + 1) / (n - 1)) * plotW;
			const y1 = pad.t + plotH - ((h.response_time_ms - min) / (max - min || 1)) * plotH;
			const y2 = pad.t + plotH - ((next.response_time_ms - min) / (max - min || 1)) * plotH;
			return {
				x1, y1, x2, y2,
				color: h.is_up && next.is_up ? 'var(--green)' : 'var(--red)'
			};
		});
	});

	let dots = $derived(
		chartHistory.map((h, i) => {
			const { min, max } = yAxis;
			const x = pad.l + (i / (Math.max(chartHistory.length - 1, 1))) * plotW;
			const y = pad.t + plotH - ((h.response_time_ms - min) / (max - min || 1)) * plotH;
			return { x, y, ...h };
		})
	);

	let areaPath = $derived.by(() => {
		if (chartHistory.length < 2) return '';
		const { min, max } = yAxis;
		const baseline = pad.t + plotH;
		const top = dots.map((d) => `${d.x},${d.y}`).join(' L ');
		const bottom = dots.map((d) => d.x).reverse().map((x) => `${x},${baseline}`).join(' L ');
		return `M ${top} L ${bottom} Z`;
	});

	let pages = $derived.by(() => {
		const p: (number | string)[] = [];
		const total = totalPages;
		if (total <= 7) {
			for (let i = 1; i <= total; i++) p.push(i);
		} else {
			p.push(1);
			if (currentPage > 3) p.push('...');
			const start = Math.max(2, currentPage - 1);
			const end = Math.min(total - 1, currentPage + 1);
			for (let i = start; i <= end; i++) p.push(i);
			if (currentPage < total - 2) p.push('...');
			p.push(total);
		}
		return p;
	});
</script>

<svelte:head>
	<title>{svc?.name ?? 'Detalhes'} — YAUM</title>
</svelte:head>

{#if loading}
	<div class="flex items-center justify-center py-20">
		<div
			class="h-8 w-8 animate-spin rounded-full border-2 border-[var(--border-color)] border-t-[var(--green)]"
		></div>
	</div>
{:else if !svc}
	<div class="rounded-xl border border-[var(--border-color)] p-12 text-center">
		<p class="text-sm text-[var(--text-muted)]">Serviço não encontrado</p>
	</div>
{:else}
	<div class="mb-6">
		<a
			href="/"
			class="text-xs text-[var(--text-muted)] underline transition-colors hover:text-white"
		>
			← Voltar
		</a>
	</div>

	<div class="mb-8">
		<h1 class="text-2xl font-semibold text-white">{svc.name}</h1>
		<p class="mt-1 font-mono text-sm text-[var(--text-secondary)]">{svc.url}</p>
	</div>

	<div class="grid gap-6 lg:grid-cols-3">
		<!-- Stats card -->
		{#if stats}
			<div class="rounded-xl border border-[var(--border-color)] bg-[var(--bg-card)] p-5">
				<h2 class="mb-4 text-sm font-semibold uppercase tracking-wider text-[var(--text-secondary)]">
					Uptime
				</h2>
				<div class="space-y-3">
					{#each [
						{ label: '24h', uptime: stats.uptime_24h, checks: stats.total_checks_24h, avg: stats.avg_response_ms_24h },
						{ label: '7 dias', uptime: stats.uptime_7d, checks: stats.total_checks_7d, avg: stats.avg_response_ms_7d },
						{ label: '30 dias', uptime: stats.uptime_30d, checks: stats.total_checks_30d, avg: stats.avg_response_ms_30d }
					] as item}
						<div class="rounded-lg border border-[var(--border-color)] bg-[var(--bg-secondary)]/30 p-3">
							<div class="mb-1 flex items-center justify-between">
								<span class="text-[10px] font-medium uppercase tracking-wider text-[var(--text-muted)]">
									{item.label}
								</span>
								<span class="font-mono text-xs tabular-nums text-[var(--text-secondary)]">
									{item.checks} checks
								</span>
							</div>
							<div class="flex items-baseline gap-3">
								<span
									class="text-lg font-bold tabular-nums"
									style="color: {item.uptime >= 99 ? 'var(--green)' : item.uptime >= 95 ? '#facc15' : 'var(--red)'}"
								>
									{item.uptime.toFixed(2)}%
								</span>
								<span class="font-mono text-xs text-[var(--text-muted)]">
									{item.avg.toFixed(0)}ms méd.
								</span>
							</div>
						</div>
					{/each}
				</div>
			</div>
		{/if}

		<!-- Tempo de Resposta (ms) -->
		<div
			class="rounded-xl border border-[var(--border-color)] bg-[var(--bg-card)] p-5 lg:col-span-2"
		>
			<h2 class="mb-4 text-sm font-semibold uppercase tracking-wider text-[var(--text-secondary)]">
				Tempo de Resposta (ms)
			</h2>
			<div bind:clientWidth={containerWidth} class="relative" style="height: 200px">
				{#if chartHistory.length === 0}
					<div class="flex h-full items-center justify-center text-xs text-[var(--text-muted)]">
						Sem dados ainda
					</div>
				{:else if chartHistory.length === 1}
					<div class="flex h-full flex-col items-center justify-center gap-1">
						<span
							class="text-3xl font-bold tabular-nums"
							style="color: {chartHistory[0].is_up ? 'var(--green)' : 'var(--red)'}"
						>
							{chartHistory[0].response_time_ms}
							<span class="text-base font-normal text-[var(--text-secondary)]">ms</span>
						</span>
						<span class="text-xs text-[var(--text-muted)]">
							{chartHistory[0].is_up ? 'Online' : 'Offline'} —
							{chartHistory[0].status_code || 'timeout'}
						</span>
					</div>
				{:else}
					<svg width={containerWidth} height={chartH}>
						<defs>
							<linearGradient id="areaGrad" x1="0" y1="0" x2="0" y2="1">
								<stop offset="0%" stop-color="var(--green)" stop-opacity="0.15" />
								<stop offset="100%" stop-color="var(--green)" stop-opacity="0.01" />
							</linearGradient>
						</defs>

						<!-- grid horizontal -->
						{#each yAxis.ticks as tick}
							<line
								x1={pad.l}
								y1={tick.y}
								x2={containerWidth - pad.r}
								y2={tick.y}
								stroke="var(--border-color)"
								stroke-width="1"
								stroke-dasharray="3,3"
							/>
							<text
								x={pad.l - 6}
								y={tick.y + 3}
								text-anchor="end"
								fill="var(--text-muted)"
								font-size="9"
							>{tick.val}</text
							>
						{/each}

						<!-- área preenchida -->
						<path d={areaPath} fill="url(#areaGrad)" />

						<!-- segmentos da linha -->
						{#each segments as seg}
							<line
								x1={seg.x1}
								y1={seg.y1}
								x2={seg.x2}
								y2={seg.y2}
								stroke={seg.color}
								stroke-width="2"
								stroke-linecap="round"
							/>
						{/each}

						<!-- pontos -->
						{#each dots as d}
							<circle
								cx={d.x}
								cy={d.y}
								r="3"
								fill={d.is_up ? 'var(--green)' : 'var(--red)'}
								stroke="var(--bg-card)"
								stroke-width="1.5"
							/>
						{/each}
					</svg>

					<!-- eixo X: tempo -->
					<div class="flex justify-between" style="padding-left: {pad.l}px; padding-right: {pad.r}px;">
						<span class="text-[10px] text-[var(--text-muted)]">
							{new Date(chartHistory[0].tested_at).toLocaleTimeString('pt-BR', { hour: '2-digit', minute: '2-digit' })}
						</span>
						<span class="text-[10px] text-[var(--text-muted)]">
							{new Date(chartHistory[chartHistory.length - 1].tested_at).toLocaleTimeString('pt-BR', { hour: '2-digit', minute: '2-digit' })}
						</span>
					</div>
				{/if}
			</div>
		</div>

		<!-- Histórico paginado -->
		<div class="rounded-xl border border-[var(--border-color)] bg-[var(--bg-card)] p-5 lg:col-span-3">
			<h2 class="mb-4 text-sm font-semibold uppercase tracking-wider text-[var(--text-secondary)]">
				Histórico de Verificações
			</h2>

			<div class="flex flex-col gap-1.5">
				{#each tableData as h}
					<div>
						<div class="flex items-center justify-between gap-2">
							<div class="flex items-center gap-2">
								<span
									class="h-2 w-2 shrink-0 rounded-full"
									class:bg-[var(--green)]={h.is_up}
									class:bg-[var(--red)]={!h.is_up}
								></span>
								<span class="font-mono text-xs">
									{#if h.status_code > 0}
										{h.status_code}
									{:else}
										TIMEOUT
									{/if}
								</span>
							</div>
							<div class="flex items-center gap-2">
								<span class="font-mono text-xs text-[var(--text-muted)]">{h.response_time_ms}ms</span>
								{#if h.error_message}
									<button
										onclick={() => (expandedError = expandedError === h.id ? null : h.id)}
										class="text-[10px] text-[var(--red)] underline underline-offset-2 transition-colors hover:opacity-70"
									>
										{expandedError === h.id ? '▲ erro' : '▼ erro'}
									</button>
								{/if}
							</div>
						</div>
						{#if expandedError === h.id && h.error_message}
							<div
								class="mt-1.5 overflow-auto rounded-md border border-[var(--red)]/20 bg-[var(--bg-secondary)]/50 p-2"
							>
								<pre class="break-all font-mono text-[11px] leading-relaxed text-[var(--text-muted)]"
									>{h.error_message}</pre
								>
							</div>
						{/if}
					</div>
				{/each}
			</div>

			<!-- Paginação -->
			{#if totalPages > 1}
				<div class="mt-5 flex items-center justify-center gap-1.5">
					<button
						onclick={() => loadTablePage(currentPage - 1)}
						disabled={currentPage <= 1}
						class="rounded-lg px-2.5 py-1.5 text-xs font-medium transition-colors disabled:cursor-not-allowed disabled:opacity-30"
						style="color: var(--text-muted); {currentPage <= 1 ? '' : 'hover:bg-[var(--border-color)] hover:text-white'}"
					>
						Anterior
					</button>

					{#each pages as p}
						{#if p === '...'}
							<span class="px-1 text-xs text-[var(--text-muted)]">…</span>
						{:else}
							<button
								onclick={() => loadTablePage(p as number)}
								class="min-w-[28px] rounded-lg px-2 py-1.5 text-xs font-medium transition-all"
								style={p === currentPage
									? 'background-color: var(--green); color: #000; font-weight: 700;'
									: 'color: var(--text-muted); hover:background-color: var(--border-color); hover:color: white;'}
							>
								{p}
							</button>
						{/if}
					{/each}

					<button
						onclick={() => loadTablePage(currentPage + 1)}
						disabled={currentPage >= totalPages}
						class="rounded-lg px-2.5 py-1.5 text-xs font-medium transition-colors disabled:cursor-not-allowed disabled:opacity-30"
						style="color: var(--text-muted); {currentPage >= totalPages ? '' : 'hover:bg-[var(--border-color)] hover:text-white'}"
					>
						Próximo
					</button>
				</div>

				<p class="mt-2 text-center text-[10px] text-[var(--text-muted)]">
					Página {currentPage} de {totalPages} — {totalItems} verificações no total
				</p>
			{/if}
		</div>
	</div>
{/if}
